package com.geek.novel.view.rate

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import com.geek.novel.R
import com.geek.novel.utils.LogCatUtil
import kotlin.math.ceil
import kotlin.math.roundToInt


/**
 * 星星评分
 */
class RateStar : View {

    private var starDistance = 0 //星星间距
    private var starCount = 5 //星星个数
    //星星高度大小，星星一般正方形，宽度等于高度
    private var starSize = 0
    //评分星星
    private var starMark = 0.0f
    //亮星星
    private var starFillBitmap: Bitmap? = null
    //暗星星
    private var starEmptyDrawable: Drawable? = null
    //监听星星变化接口
    private var onStarChangeListener: OnStarChangeListener? = null
    //绘制星星画笔
    private var paint: Paint? = null
    private var integerMark = false

    //是否只读
    private var readonly = false

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        init(context, attrs)
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        init(context, attrs)
    }

    /**
     * 初始化UI组件
     *
     * @param context
     * @param attrs
     */
    @SuppressLint("CustomViewStyleable")
    private fun init(context: Context, attrs: AttributeSet) {
        isClickable = true
        val mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RatingBar)
        starDistance = mTypedArray.getDimension(R.styleable.RatingBar_starDistance, 0f).toInt()
        starSize = mTypedArray.getDimension(R.styleable.RatingBar_starSize, 20f).toInt()
        starCount = mTypedArray.getInteger(R.styleable.RatingBar_starCount, 5)
        starEmptyDrawable = mTypedArray.getDrawable(R.styleable.RatingBar_starEmpty)
        starFillBitmap = drawableToBitmap(mTypedArray.getDrawable(R.styleable.RatingBar_starFill))
        readonly = mTypedArray.getBoolean(R.styleable.RatingBar_readonly, false)
        mTypedArray.recycle()
        paint = Paint()
        paint!!.isAntiAlias = true
        paint!!.shader = BitmapShader(starFillBitmap!!, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
    }

    /**
     * 设置是否需要整数评分
     * @param integerMark
     */
    fun setIntegerMark(integerMark: Boolean) {
        this.integerMark = integerMark
    }

    /**
     * 设置显示的星星的分数
     * @param mark
     */
    fun setStarMark(mark: Float) {
        starMark = if (integerMark) {
            ceil(mark.toDouble()).toInt().toFloat()
        } else {
            (mark * 10).roundToInt() * 1.0f / 10
        }
        if (onStarChangeListener != null) {
            onStarChangeListener!!.onStarChange(starMark) //调用监听接口
        }
        invalidate()
    }

    /**
     * 获取显示星星的数目
     * @return starMark
     */
    fun getStarMark(): Float {
        return starMark
    }

    /**
     * 是否只读
     */
    fun setReadonly(readonly: Boolean){
        this.readonly = readonly
    }

    /**
     * 是否只读
     */
    fun isReadonly(): Boolean{
        return this.readonly
    }

    /**
     * 定义星星点击的监听接口
     */
    interface OnStarChangeListener {
        fun onStarChange(mark: Float)
    }

    /**
     * 设置监听
     * @param onStarChangeListener
     */
    fun setOnStarChangeListener(onStarChangeListener: OnStarChangeListener?) {
        this.onStarChangeListener = onStarChangeListener
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        setMeasuredDimension(starSize * starCount + starDistance * (starCount - 1), starSize)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        if (starFillBitmap == null || starEmptyDrawable == null) {
            return
        }
        for (i in 0 until starCount) {
            starEmptyDrawable!!.setBounds(
                (starDistance + starSize) * i,
                0,
                (starDistance + starSize) * i + starSize,
                starSize
            )
            starEmptyDrawable!!.draw(canvas)
        }
        if (starMark > 1) {
            canvas.drawRect(0f, 0f, starSize.toFloat(), starSize.toFloat(), paint!!)
            if (starMark - starMark.toInt() == 0f) {
                var i = 1
                while (i < starMark) {
                    canvas.translate((starDistance + starSize).toFloat(), 0f)
                    canvas.drawRect(0f, 0f, starSize.toFloat(), starSize.toFloat(), paint!!)
                    i++
                }
            } else {
                var i = 1
                while (i < starMark - 1) {
                    canvas.translate((starDistance + starSize).toFloat(), 0f)
                    canvas.drawRect(0f, 0f, starSize.toFloat(), starSize.toFloat(), paint!!)
                    i++
                }
                canvas.translate((starDistance + starSize).toFloat(), 0f)
                canvas.drawRect(
                    0f, 0f,
                    starSize * (Math.round((starMark - starMark.toInt()) * 10) * 1.0f / 10),
                    starSize.toFloat(), paint!!
                )
            }
        } else {
            canvas.drawRect(0f, 0f, starSize * starMark, starSize.toFloat(), paint!!)
        }
    }

    override fun performClick(): Boolean {
        LogCatUtil.d(this.javaClass.simpleName, "触发performClick事件")
        return super.performClick()
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        if(this.isReadonly()){
            return false
        }
        var x = event.x.toInt()
        if (x < 0) x = 0
        if (x > measuredWidth) x = measuredWidth
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                this.performClick()
                setStarMark(x * 1.0f / (measuredWidth * 1.0f / starCount))
            }
            MotionEvent.ACTION_MOVE -> {
                setStarMark(x * 1.0f / (measuredWidth * 1.0f / starCount))
            }
            MotionEvent.ACTION_UP -> {
            }
        }
        invalidate()
        return super.onTouchEvent(event)
    }

    /**
     * drawable转bitmap
     *
     * @param drawable
     * @return
     */
    private fun drawableToBitmap(drawable: Drawable?): Bitmap? {
        if (drawable == null) return null
        val bitmap = Bitmap.createBitmap(starSize, starSize, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, starSize, starSize)
        drawable.draw(canvas)
        return bitmap
    }
}


